/**
 * Framework for batch testing user profile models
 * Final project by Sergey Nepomnyachiy and Julia Polchin
 * Supervisor: Tsvi Kuflik
 *
 */
package backend;

import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

/**
 * Class providing static methods for statistical analysis
 * @author Sergey and Julia
 *
 */
@SuppressWarnings("boxing")
public class Stats {

	/**
	 * Given two variables calculate the correlation coefficient for them (linear regression)
	 * Assuming left less or equal in size to right
	 * @param left First set of data
	 * @param right Second set of data
	 * @return Correlation coefficient of the two sets
	 */
	public static Double getCorrelation(Collection<?> left, Collection<?> right) {
		if (left.isEmpty() || right.isEmpty())
			return Double.NaN;
		
		Double corr = 0.0;
		
		Vector<Double> dataX = convert(left);
		Vector<Double> dataY = convert(right);
		Iterator<Double> itx = dataX.iterator();
		Iterator<Double> ity = dataY.iterator();
		
		Double sx = 0.0;
		Double sy = 0.0;
		Double sxy = 0.0;
		Double sx2 = 0.0;
		Double sy2 = 0.0;
		Double size = dataX.size() + 0.0;

		while (itx.hasNext()) {
			
			Double x = itx.next();
			Double y = ity.next();
			
			sx += x; 
			sy += y;
			sxy += x*y;
			sx2 += x*x;
			sy2 += y*y;
		}
		
		Double sqsx = sx*sx;
		Double sqsy = sy*sy;
		
		corr = ((size*sxy) - (sx*sy)) / Math.sqrt( ((size*sx2)-sqsx)*((size*sy2)-sqsy)  ); 
/*
		System.out.println(sx);
		System.out.println(sy);
		System.out.println(sxy);
		System.out.println(sx2);
		System.out.println(sy2);
		System.out.println(corr);
		System.out.println("=================");
*/		

		//assert ( corr.compareTo(1.0) <= 0 && corr.compareTo(-1.0) >=  0);
		return corr;
	}
	
	/**
	 * Given two variables calculate the mean abslute error for them
	 * Assuming left less or equal in size to right
	 * @param left First set of data
	 * @param right Second set of data
	 * @return MAE
	 */
	public static Double getMAE(Collection<?> left, Collection<?> right) {
		if (left.isEmpty() || right.isEmpty())
			return Double.NaN;
		
		Double mae = 0.0;
		
		Vector<Double> dataX = convert(left);
		Vector<Double> dataY = convert(right);
		Iterator<Double> itx = dataX.iterator();
		Iterator<Double> ity = dataY.iterator();

		Double size = dataX.size() + 0.0;

		while (itx.hasNext()) {
			mae += Math.abs(itx.next()-ity.next()); 
		}
		
		return mae / size;
	}
	
	/**
	 * Used to convert Collection<?> to Vector<Double>
	 * We support only 2 arithmetic types - double and integer 
	 * @param data data set
	 * @return vector of double values from data collection 
	 */
	public static Vector<Double> convert(Collection<?> data) {
		Vector<Double> result = new Vector<Double>();
		for (Object obj : data ) {
			if ( obj instanceof Double)
				result.add( (Double) obj);
			else if ( obj instanceof Integer)
				result.add( 0.0 + (Integer) obj);
			else 
				result.add( 0.0 );
		}
		return result;
	}
}
